<!--
 * @Author: GuitarXiaohe 2205227953@qq.com
 * @Date: 2024-06-28 09:31:15
 * @LastEditors: GuitarXiaohe 2205227953@qq.com
 * @LastEditTime: 2024-06-28 14:30:50
 * @Description: 根据vxe组件封装
-->
<script setup name="p-table-form">
import { computed } from "vue";
import Sortable from "sortablejs";

/**
 * 获取实例vue3
 */
const { proxy } = getCurrentInstance();

/**
 * 此组件通过vxe魔改
 * !? 当前组件只用于表单使用 ！！！
 * !!当前组件配置字段多 请认真查看配置项
 */
const props = defineProps({
  /**
   * 新增文字
   */
  title: { type: String, default: "添加产品" },

  /**
   * 是否显示添加按钮
   */
  isAdd: { type: Boolean, default: false },
  // 列表主键id（必须设置且自动带出）
  keyId: {
    required: false,
    type: String,
    default: "id",
  },
  /**
   * 数据
   */
  data: {
    required: true,
    type: Array,
    default: () => [],
  },
  /**
 /**
   *  列表每一列
   * @param { string} label 表头
   * @param { string} prop 字段变量
   * @param { boolean} showText 文字溢出是否需要显示文字（非必填）
   * @param { string} width 宽度
   * @param { string} fixed 固定列
   */
  column: {
    required: true,
    type: Array,
    default: () => [],
  },
  /**
   * 是否展开
   */
  defaultExpandAll: {
    type: Boolean,
    default: false,
  },
  /**
   * !!弃用
   * 拖动class（需要提供本身或上级calss）
   */
  className: {
    type: String,
    default: "",
    required: false,
  },
  /**
   * 加载状态
   */
  loading: {
    type: Boolean,
    default: false,
    required: false,
  },
  /**
   * 高度
   */
  height: {
    type: [String, Number],
    default: 320,
    required: false,
  },
  /**
   * 值为空是 显示
   */
  empty: {
    type: String,
    default: "--",
    required: false,
  },
  /**
   * 是否需要序号
   */
  index: {
    type: Boolean,
    default: true,
    required: false,
  },
  /**
   * 是否需要复选
   */
  isSel: {
    type: Boolean,
    default: true,
  },
  /**
   * 是否需要边框
   */
  border: {
    type: Boolean,
    default: true,
  },
  /**
   * 是否需要斑马线
   */
  stripe: {
    type: Boolean,
    default: true,
  },
  /**
   * !!（与多选二选一）
   * 是否需要单选
   */
  isRadio: {
    type: Boolean,
    default: false,
  },
});

/**
 * 注册事件名称
 */
const emit = defineEmits(["current-change", "change", "listChange"]);

/**
 * 异常说明
 */
const errorMsg = reactive({
  1: "传入数据类型错误,类型应为数组!",
  2: '传入"column"数据错误,prop属性不能重复!',
  3: "当isRadio启用时,必须传入keyId作为唯一标识!",
  4: `当前keyId为${props.keyId},获取不到主键ID,请传入正确keyId`,
});

/**
 * 白名单 判断是否需要 show-overflow-tooltip
 * 一般 操作按钮 开关 标签不需要show-overflow-tooltip 就设置白名单
 * 可设置prop为这些参数,或者设置label同样效果
 */
const whiteList = ref(["x", "操作", "状态"]);

/**
 * 全选
 * 给出下标 方便查到或删除
 * @param {*} result
 */
const selectAllChangeEvent = ({ checked }) => {
  const $table = proxy.$refs.tableRef;
  if ($table) {
    const records = $table.getCheckboxRecords();
    try {
      emit("change", {
        ids: [],
        index: records.map((item) => item["index"]),
        row: records,
      });
    } catch (err) {
      throw "p-table组件:" + err;
    }
  }
};

/**
 * 复选勾选 反馈父级组件事件
 * @param {*} result
 */
const selectionChange = (result) => {
  const row = result.records;
  try {
    emit("change", {
      ids: [],
      uids: row.map((item) => item["uid"]),
      index: row.map((item) => item["index"]),
      row: row,
    });
  } catch (err) {
    throw "p-table组件:" + err;
  }
};

/**
 * 目前系统业务场景使用不到
 * 单选勾选
 * @param {*} result
 */
const radioChangeEvent = (result) => {
  const selection = result.row;
  try {
    // 点击一行时触发
    // emit("current-change", { ids: selection[props.keyId], row: selection });
    // 如果不是单选 禁止 以下操作
    if (!props.isRadio) return;
    // 判断keyId是否正确
    if (props.isRadio) {
      if (!selection[props.keyId]) {
        throw errorMsg["3"];
      }
    }
    emit("change", { ids: selection[props.keyId], row: selection });
  } catch (err) {
    throw "p-table组件:" + err;
  }
};

/**
 * 筛选 是否有重复 prop（当前停用校验，开发环境容易造成浏览器卡死）
 */
const tableColumn = computed(() => {
  // const newData = Array.from(new Set(props.column.map((t) => t.prop)));
  // if (props.column.length > newData.length) {
  //   throw "p-table组件:" + errorMsg["2"];
  // } else {
  //   return props.column.filter((t) => !t.disabled);
  // }
  return props.column.filter((t) => !t.disabled);
});

/**
 * 数据为空的时候做出显示 给予提示
 * @param {*} val
 * @param {*} key
 * @param {*} label
 * @param {*} scope
 */
const getData = (val, key, label, scope) => {
  try {
    if (val && key && val[key] != null && val[key] != undefined) {
      return val[key];
    } else {
      if (props.empty) {
        return props.empty;
      } else if (!key) {
        return `" ${label} " 的 "prop" 为空`;
      } else {
        return `" ${label} "为空, ${key} -> " ${val[key]} "`;
      }
    }
  } catch (err) {
    throw "p-table组件:" + err;
  }
};

/**
 * 判断是否类型错误
 * 给出下标 方便查到或删除
 */
const list = computed(() => {
  if (!Array.isArray(props.data)) {
    throw "p-table组件:" + errorMsg["1"];
  } else {
    // 单选时,数据刷新默认选中一项
    if (props.data.length > 0 && props.isRadio) {
      const obj = props.data[0];
      // 如果为空 抛出异常
      if (!obj[props.keyId]) {
        throw "p-table组件:" + errorMsg["4"];
      }
    }
    // 数据参入下标
    props.data.forEach((t, ind) => (t["index"] = ind));

    return props.data || [];
  }
});

/**
 * 校验表格
 * 此方法通过循环校验每个表单元素
 * 如果出现校验未通过 抛出异常但是不停止循环 继续校验 直到结束
 * @returns Promise
 */
const validate = async () => {
  const elements = await proxy.$refs.itemFormRef;
  if (!Array.isArray(elements))
    return console.log(
      "%cp-table-form组件:列表数据错误 => " + typeof elements,
      "color:red;font-size:14px"
    );
  elements.forEach((t) => t.validate());
  return new Promise(async (resolve, reject) => {
    try {
      for (let index = 0; index < elements.length; index++) {
        await elements[index].validate();
      }
      resolve(true);
    } catch (err) {
      console.log("校验表格err", err);
      proxy.warningMsg("列表校验未通过,请注意查看!");
      reject("校验表格err");
    }
  });
};

/**
 * 开发环境专用测试校验
 */
const wthere = async () => {
  await validate();
};

/**
 * 判断是否需要 show-overflow-tooltip
 */
const isShowText = (val) => {
  if (val.label == "备注") {
    return true;
  } else if (val.label == "辅助属性") {
    return false;
  } else if (
    whiteList.value.includes(val.label) ||
    whiteList.value.includes(val.prop) ||
    val.prop?.length < 2
  ) {
    return false;
  } else {
    return true;
  }
};

/**
 * 校验错误提示
 * 触发校验不通过给出背景色位红色 更显著 目前未启用
 */
const cellClassName = (a) => {
  // console.log(a);
  // console.log(column, "column");
  // console.log(row, "row");
  // if (column.field === "sex") {
  //   if (row.sex >= "1") {
  //     return "col-red";
  //   } else if (row.age === 26) {
  //     return "col-orange";
  //   }
  // }
  // return null;
};

/**
 * 开发环境判断
 */
const isShow = computed(() => import.meta.env.VITE_APP_ENV == "development");

defineExpose({
  validate,
});
</script>

<template>
  <div class="p-table">
    <div class="flex">
      <el-button v-if="isShow" @click="wthere"
        >开发环境专用(查看是否校验通过)</el-button
      >
      <!-- 新增 -->
      <div>
        <el-button v-if="props.isAdd" @click="emit('add')">{{
          props.title || "添加产品"
        }}</el-button>
      </div>
    </div>
    <vxe-table
      border
      show-overflow
      :column-config="{ resizable: true }"
      ref="tableRef"
      :data="list"
      :height="props.height"
      class="tableClass"
      auto-resize
      :cell-class-name="cellClassName"
      :checkbox-config="{ checkField: 'checked', trigger: 'row' }"
      @checkbox-change="selectionChange"
      @cell-click="currentChange"
      @checkbox-all="selectAllChangeEvent"
    >
      <vxe-column type="seq" width="60" />
      <vxe-column v-if="props.isSel" type="checkbox" width="60" />
      <vxe-column
        v-for="(columnItem, index) in tableColumn"
        :key="`p-table-form-${columnItem.prop}-${index}`"
        :field="columnItem.prop"
        :title="columnItem.label"
        :fixed="columnItem.fixed"
        :label="columnItem.label"
        :prop="columnItem.prop"
        :rules="columnItem.rules"
        :width="
          columnItem.width !== undefined
            ? columnItem.width
            : columnItem.label.includes('单号') ||
              columnItem.label.includes('物资编码') ||
              columnItem.label.includes('物资名称') ||
              columnItem.label.includes('物资类别')
            ? '220'
            : columnItem.label == '操作'
            ? '300'
            : '250'
        "
        :show-overflow-tooltip="
          columnItem.showText === undefined
            ? isShowText(columnItem)
            : columnItem.showText
        "
      >
        <template #header>
          <div>
            <span style="color: red" v-if="columnItem.required">*</span>
            <span> {{ columnItem.label }}</span>
          </div>
        </template>
        <!--   -->
        <template #default="scope">
          <el-form
            scroll-to-error
            class="formClass"
            ref="addFormRef"
            :model="scope.row"
            label-width="0px"
            inline
          >
            <el-form-item
              ref="itemFormRef"
              class="itemForm"
              label=""
              :rules="
                columnItem.rules || [
                  {
                    required: columnItem.required,
                    message: `请输入或者选择${columnItem.label}`,
                    trigger: columnItem.type == '输入框' ? 'blur' : 'change',
                  },
                ]
              "
              :prop="columnItem.required ? columnItem.prop : null"
            >
              <slot
                class="ccc"
                name="columnCell"
                :record="scope.row"
                :scope="{ ...scope, $index: scope.$rowIndex }"
                :column="{
                  prop: columnItem.prop,
                  label: columnItem.label,
                  width: columnItem.width,
                }"
              >
                {{
                  getData(scope.row, columnItem.prop, columnItem.label, scope)
                }}
              </slot>
            </el-form-item>
          </el-form>
        </template>
      </vxe-column>
      <!-- 开发环境使用 线上自动取消 -->
      <template #empty v-if="isShow">
        <span style="color: red">
          <img
            src="https://pic2.zhimg.com/50/v2-f7031359103859e1ed38559715ef5f3f_hd.gif"
          />
          <p>不用再看了，没有更多数据了！</p>
        </span>
      </template>
    </vxe-table>
  </div>
</template>
<style scoped lang="scss">
.p-table {
  width: 100%;
  .flex {
    justify-content: space-between;
  }
}

.p-table ::v-deep .vxe-table--body {
  margin-bottom: 70px !important;
}

.itemForm {
  width: 100% !important;
}

.tableClass {
  width: 100% !important;
  margin-top: 0.9375rem;
}
.ccc {
  text-overflow: ellipsis;
}

.tableClass ::-webkit-scrollbar {
  width: 10px;
  height: 10px;
}

/*滚动条的轨道*/
.tableClass ::-webkit-scrollbar-track {
  background-color: #ffffff;
}

/*滚动条里面的小方块，能向上向下移动*/
.tableClass ::-webkit-scrollbar-thumb {
  background-color: #bfbfbf;
  border-radius: 5px;
  border: 1px solid #f1f1f1;
  box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
}

.tableClass ::-webkit-scrollbar-thumb:hover {
  background-color: #a8a8a8;
}

.tableClass ::-webkit-scrollbar-thumb:active {
  background-color: #787878;
}

/*边角，即两个滚动条的交汇处*/
.tableClass ::-webkit-scrollbar-corner {
  background-color: #ffffff;
}

::v-deep(.mytable-style.vxe-table .vxe-body--row.row-green) {
  background-color: #187;
  color: #fff;
}
::v-deep(.mytable-style.vxe-table .vxe-header--column.col-blue) {
  background-color: #2db7f5;
  color: #fff;
}
::v-deep(.mytable-style.vxe-table .vxe-body--column.col-red) {
  background-color: red;
  color: #fff;
}
::v-deep(.vxe-body--column) {
  height: auto !important;
  padding-top: 15px;
}
</style>
